#include"Log.hpp"

#include<sys/types.h>
#include<sys/socket.h>
#include<string>
#include<cerrno>
#include<cstring>
#include<jsoncpp/json/json.h>

namespace bobo
{
    // #define MYSELF 0

    #define SPACE " "
    #define SPACE_LEN strlen(SPACE)
    #define SEP "\r\n"
    #define SEP_LEN strlen(SEP)

    class Request
    {
    public:
        Request(int x = 0, int y = 0, char op = '+')
            :_x(x)
            ,_y(y)
            ,_op(op)
        {}
        std::string Serialize()
        {
#ifdef MYSELF
            std::string str;
            str = std::to_string(_x);
            str += SPACE;
            str += _op; // TODO
            str += SPACE;
            str += std::to_string(_y);
            return str;
#else
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["op"] = _op;
            Json::FastWriter writer;
            return writer.write(root);
#endif
        }
        bool Deserialize(const std::string& str)
        {
#ifdef MYSELF
            std::size_t left = str.find(SPACE);
            if (left == std::string::npos)
                return false;
            std::size_t right = str.rfind(SPACE);
            if (right == std::string::npos)
                return false;
            _x = atoi(str.substr(0, left).c_str());
            _y = atoi(str.substr(right + SPACE_LEN).c_str());
            if (left + SPACE_LEN > str.size())
                return false;
            else
                _op = str[left + SPACE_LEN];
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(str, root);
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["op"].asInt();
            return true;
#endif
        }
    public:
        int _x;
        int _y;
        char _op;
    };

    class Response
    {
    public:
        Response(int result = 0, int code = 0)
            :_result(result)
            ,_code(code)
        {}
        std::string Serialize()
        {
#ifdef MYSELF
            std::string s;
            s = std::to_string(_code);
            s += SPACE;
            s += std::to_string(_result);
            return s;
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter writer;
            return writer.write(root);
#endif
        }
        bool Deserialize(const std::string& s)
        {
#ifdef MYSELF
            std::size_t pos = s.find(SPACE);
            if (pos == std::string::npos)
                return false;
            _code = atoi(s.substr(0, pos).c_str());
            _result = atoi(s.substr(pos + SPACE_LEN).c_str());
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(s, root);
            _result = root["result"].asInt();
            _code = root["code"].asInt();
            return true;
#endif
        }
    public:
        int _result;
        int _code;
    };

    void Send(int sock, const std::string& str)
    {
        send(sock, str.c_str(), str.size(), 0);
    }

    bool Recv(int sock, std::string* pInbuffer)
    {
        char buffer[1024];
        ssize_t s = recv(sock, buffer, sizeof buffer, 0);
        if(s > 0) 
        {
            buffer[s] = 0;
            *pInbuffer += buffer;
            return true;
        }
        else if(s == 0)
        {
            logMessage(NORMAL, "opposite quit, me too...\n");
            return false;
        }
        else
        {
            logMessage(FATAL, "recv fail[%d]: %s\n", errno, strerror(errno));
            return false;
        }
    }
    // length\r\n123 + 456\r\n
    std::string Decode(std::string& inbuffer)
    {
        size_t pos = inbuffer.find(SEP);
        if(pos == std::string::npos) return "";

        size_t length = stoi(inbuffer.substr(0, pos));
        size_t size = inbuffer.size() - pos - 2 * SEP_LEN;
        if(size < length) return "";

        std::string package = inbuffer.substr(pos + SEP_LEN, length);
        inbuffer.erase(0, pos + 2*SEP_LEN + length);
        return package;
    }
    std::string Encode(const std::string& s)
    {
        std::string package;
        package += std::to_string(s.size());
        package += "\r\n";
        package += s;
        package += "\r\n";
        return package;
    }
}